﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.IO;
using System.IO.IsolatedStorage;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Media.Imaging;

namespace MyChannel.DownloadComponent
{
    public class Download : INotifyPropertyChanged
    {

        public event PropertyChangedEventHandler PropertyChanged;
        protected virtual void OnPropertyChanged(string propChanged)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(propChanged));
        }
        IsolatedStorageFile file = IsolatedStorageFile.GetUserStoreForApplication();

        private LocalVideo _video;
        public LocalVideo Video
        {
            get { return _video; }
            set
            {
                if (_video != value)
                {
                    _video = value;
                    OnPropertyChanged("Video");
                }
            }
        }


        private float _progress;
        public float Progress
        {
            get { return _progress; }
            set
            {
                if (_progress != value)
                {
                    _progress = value;
                    OnPropertyChanged("Progress");
                }
            }
        }

        public Download Reference
        {
            get { return this; }
        }

        private long TotalLength { get; set; }

        IsolatedStorageFileStream streamToWriteTo;
        HttpWebRequest request;

        public void StartDownload()
        {
            _video.currentDispatcher = Deployment.Current.Dispatcher;
            _video.State = "Downloading";
            if (!file.DirectoryExists(App.DIRECTORY_SAVE_DOWNLOAD))
            {
                file.CreateDirectory(App.DIRECTORY_SAVE_DOWNLOAD);
            }
            if (file.FileExists(App.DIRECTORY_SAVE_DOWNLOAD + _video.Name))
            {
                foreach (LocalVideo video in App.ViewModel.VideoList)
                {
                    if (video.Key == _video.Key && video.State == "Completed")
                    {
                        _video.State = "Completed";
                        if (ModelLocator.HomeStatic.Downloads.Count != 0)
                        {
                            foreach (Download d in ModelLocator.HomeStatic.Downloads)
                            {
                                if (d.Video.State == "Pending")
                                {
                                    d.StartDownload();
                                    break;
                                }
                            }
                        }
                        System.Windows.Deployment.Current.Dispatcher.BeginInvoke(new Action(() =>
                        {
                            App.ViewModel.SaveChangesToDB();
                            ModelLocator.HomeStatic.Downloads.Remove(this);
                        }
                        ));
                        return;
                    }
                }
            }
            streamToWriteTo = new IsolatedStorageFileStream(App.DIRECTORY_SAVE_DOWNLOAD + _video.Name, FileMode.Create, file);
            request = (HttpWebRequest)WebRequest.Create(new Uri(_video.Url, UriKind.RelativeOrAbsolute));
            request.AllowReadStreamBuffering = false;
            request.BeginGetResponse(new AsyncCallback(GetData), request);
        }

        void GetData(IAsyncResult result)
        {
            HttpWebRequest request = (HttpWebRequest)result.AsyncState;

            try
            {
        
                    HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(result);
                    Stream rStream = response.GetResponseStream();
                    IsolatedStorageFile file = IsolatedStorageFile.GetUserStoreForApplication();

                    byte[] data = new byte[16 * 1024];
                    int read;

                    long totalValue = response.ContentLength;


                    long sum = 0;

                    while ((read = rStream.Read(data, 0, data.Length)) > 0)
                    {
                        sum += read;

                        System.Windows.Deployment.Current.Dispatcher.BeginInvoke(new Action(() => Progress = (int)((sum * 10000) / totalValue)/100f ));

                        streamToWriteTo.Write(data, 0, read);
                    }
                    streamToWriteTo.Close();
                    streamToWriteTo.Dispose();

                    // no success
                    if (sum < totalValue)
                    {
                        _video.State = "Pending";
                        this.StartDownload();
                        return;
                    }
     
                _video.State = "Completed";



                if (ModelLocator.HomeStatic.Downloads.Count != 0)
                {
                    foreach (Download d in ModelLocator.HomeStatic.Downloads)
                    {
                        if (d.Video.State == "Pending")
                        {
                            d.StartDownload();
                            break;
                        }
                    }
                }

                System.Windows.Deployment.Current.Dispatcher.BeginInvoke(new Action(() =>
                {
                    App.ViewModel.SaveChangesToDB();
                    ModelLocator.HomeStatic.Downloads.Remove(this);
                }
                ));
            }
            catch (Exception ex)
            {

                StopDownload();
            }
        }



        internal void StopDownload()
        {
            try
            {
                if (request != null)
                {
                    request.Abort();
                }
                if (streamToWriteTo != null)
                {
                    streamToWriteTo.Close();
                    streamToWriteTo.Dispose();
                }
                if (file.FileExists(App.DIRECTORY_SAVE_DOWNLOAD + _video.Name))
                {
                    file.DeleteFile(App.DIRECTORY_SAVE_DOWNLOAD + _video.Name);
                }
            }
            catch { }
        }
    }


    public class DownloadViewModel : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
        protected virtual void OnPropertyChanged(string propChanged)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(propChanged));
        }
        private ObservableCollection<Download> _downloads;
        public ObservableCollection<Download> Downloads
        {
            get
            {
                return _downloads;
            }
            set
            {
                if (_downloads != value)
                {
                    _downloads = value;
                    OnPropertyChanged("Downloads");
                }
            }
        }

        public Download CurrentDownload { get; set; }
    }


    public class ModelLocator
    {
        private static DownloadViewModel _home;

        public ModelLocator()
        {
            HomeStatic.Downloads = new System.Collections.ObjectModel.ObservableCollection<Download>();
        }

        public static DownloadViewModel HomeStatic
        {
            get
            {
                if (_home == null)
                {
                    CreateHome();
                }

                return _home;
            }
        }

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance",
            "CA1822:MarkMembersAsStatic",
            Justification = "This non-static member is needed for data binding purposes.")]
        public DownloadViewModel BoundHomeModel
        {
            get
            {
                return HomeStatic;
            }
        }

        public static void CreateHome()
        {
            if (_home == null)
            {
                _home = new DownloadViewModel();
            }
        }

        public static void Cleanup()
        {

        }
    }
}
